import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import hj212_protocol
import socket
import threading


class Hj212SenderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("HJ212报文发送工具")
        self.root.geometry("800x600")

        # 主框架
        main_frame = ttk.Frame(root)
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)

        # 输入区域
        input_frame = ttk.LabelFrame(main_frame, text="参数设置")
        input_frame.pack(fill="x", pady=5)

        # 网络设置
        network_frame = ttk.Frame(input_frame)
        network_frame.pack(fill="x", pady=5)

        ttk.Label(network_frame, text="IP地址:").grid(row=0, column=0, sticky="w", padx=5)
        self.ip_entry = ttk.Entry(network_frame, width=20)
        self.ip_entry.grid(row=0, column=1, sticky="w", padx=5)

        ttk.Label(network_frame, text="端口号:").grid(row=0, column=2, sticky="w", padx=0)
        self.port_entry = ttk.Entry(network_frame, width=10)
        self.port_entry.grid(row=0, column=3, sticky="w", padx=0)

        ttk.Label(network_frame, text="MN号:").grid(row=0, column=4, sticky="w", padx=5)
        self.mn_entry = ttk.Entry(network_frame, width=20)
        self.mn_entry.grid(row=0, column=5, sticky="w", padx=5)

        ttk.Label(network_frame, text="ST:").grid(row=0, column=6, sticky="w", padx=5)
        self.st_entry = ttk.Entry(network_frame, width=5)
        self.st_entry.insert(0, "32")
        self.st_entry.grid(row=0, column=7, sticky="w", padx=5)

        ttk.Label(network_frame, text="Flag:").grid(row=0, column=8, sticky="w", padx=5)
        self.flag_entry = ttk.Entry(network_frame, width=5)
        self.flag_entry.insert(0, "0")
        self.flag_entry.grid(row=0, column=9, sticky="w", padx=5)

        # DataTime输入框（第二行）
        # ttk.Label(network_frame, text="DataTime:").grid(row=1, column=0, sticky="w", padx=5)
        # self.datetime_entry = ttk.Entry(network_frame, width=20, state="disabled")
        # self.datetime_entry.grid(row=1, column=1, sticky="w", padx=5)
        # ttk.Label(network_frame, text="格式: YYYYMMDDHHMMSS").grid(row=1, column=2, sticky="w", padx=5)

        # 数据类型选择
        type_frame = ttk.Frame(input_frame)
        type_frame.pack(fill="x", pady=5)

        ttk.Label(type_frame, text="数据类型:").pack(side="left", padx=5)
        self.data_type = tk.StringVar()
        self.data_type.set("实时数据")
        type_menu = ttk.OptionMenu(type_frame, self.data_type, "实时数据",
                                   *hj212_protocol.DATA_TYPES.keys())
        type_menu.pack(side="left", padx=5)

        ttk.Label(type_frame, text="DataTime:").pack(side="left", padx=5)
        self.datetime_entry = ttk.Entry(type_frame, width=20, state="disabled")
        self.datetime_entry.pack(side="left", padx=5)
        ttk.Label(type_frame, text="格式: YYYYMMDDHHMMSS").pack(side="left", padx=5)

        # 因子输入区域
        factor_frame = ttk.LabelFrame(input_frame, text="因子数据")
        factor_frame.pack(fill="both", expand=True, pady=5)

        # 因子表格
        columns = ("因子编码", "值", "Flag")
        self.factor_tree = ttk.Treeview(factor_frame, columns=columns, show="headings", height=5)

        for col in columns:
            self.factor_tree.heading(col, text=col)
            self.factor_tree.column(col, width=100, anchor="center")

        self.factor_tree.pack(fill="both", expand=True, padx=5, pady=5)

        # 因子操作按钮
        btn_frame = ttk.Frame(factor_frame)
        btn_frame.pack(fill="x", pady=5)

        ttk.Button(btn_frame, text="添加因子", command=self.add_factor).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="编辑因子", command=self.edit_factor).pack(side="left", padx=5)
        ttk.Button(btn_frame, text="删除因子", command=self.remove_factor).pack(side="left", padx=5)

        # 绑定双击编辑事件
        self.factor_tree.bind("<Double-1>", self.on_factor_double_click)

        # 监听数据类型变化
        self.data_type.trace("w", self.on_data_type_changed)

        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill="x", pady=5)

        self.send_button = ttk.Button(button_frame, text="发送报文", command=self.send_message)
        self.send_button.pack(side="left", padx=5)

        # 日志区域
        log_frame = ttk.LabelFrame(main_frame, text="日志")
        log_frame.pack(fill="both", expand=True)

        self.log_text = scrolledtext.ScrolledText(log_frame, height=15)
        self.log_text.pack(fill="both", expand=True, padx=5, pady=5)

        # 默认值
        self.ip_entry.insert(0, "127.0.0.1")
        self.port_entry.insert(0, "8000")
        self.mn_entry.insert(0, "12345678901234567890")

        # 添加示例因子
        self.add_sample_factors()

    def get_existing_factors(self):
        """获取已存在的因子编码列表"""
        return [
            self.factor_tree.item(item, "values")[0]
            for item in self.factor_tree.get_children()
        ]

    def edit_factor(self, item=None):
        """编辑因子"""
        if not item:
            item = self.factor_tree.selection()[0]

        values = self.factor_tree.item(item, "values")

        # 创建编辑对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("编辑因子")
        dialog.geometry("350x250")  # 增大窗口尺寸确保按钮可见
        dialog.resizable(False, False)  # 禁止调整大小

        # 因子编码
        ttk.Label(dialog, text="因子编码:").pack(pady=5)
        factor_entry = ttk.Entry(dialog)
        factor_entry.insert(0, values[0])
        factor_entry.pack(pady=5)

        # 因子值
        ttk.Label(dialog, text="值:").pack(pady=5)
        value_entry = ttk.Entry(dialog)
        value_entry.insert(0, values[1])
        value_entry.pack(pady=5)

        # Flag
        ttk.Label(dialog, text="Flag:").pack(pady=5)
        flag_entry = ttk.Entry(dialog)
        flag_entry.insert(0, values[2])
        flag_entry.pack(pady=5)

        # 确认按钮
        def confirm():
            factor = factor_entry.get()
            value = value_entry.get()
            flag = flag_entry.get()
            if factor:  # 确保因子编码不为空
                self.factor_tree.item(item, values=(factor, value, flag))
            dialog.destroy()

        ttk.Button(dialog, text="确认", command=confirm).pack(pady=10)

    def add_factor(self):
        """添加新因子"""
        # 创建添加因子对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("添加因子")
        dialog.geometry("350x250")  # 增大窗口尺寸确保按钮可见
        dialog.resizable(False, False)  # 禁止调整大小

        # 因子编码
        ttk.Label(dialog, text="因子编码:").pack(pady=5)
        factor_entry = ttk.Entry(dialog)
        factor_entry.pack(pady=5)

        # 因子值
        ttk.Label(dialog, text="值:").pack(pady=5)
        value_entry = ttk.Entry(dialog)
        value_entry.insert(0, "0.0")
        value_entry.pack(pady=5)

        # Flag
        ttk.Label(dialog, text="Flag:").pack(pady=5)
        flag_entry = ttk.Entry(dialog)
        flag_entry.insert(0, "N")
        flag_entry.pack(pady=5)

        # 确认按钮
        def confirm():
            factor = factor_entry.get()
            value = value_entry.get()
            flag = flag_entry.get()

            if not factor:
                messagebox.showwarning("警告", "因子编码不能为空")
                return

            if factor in self.get_existing_factors():
                messagebox.showwarning("警告", "该因子编码已存在")
                return

            self.factor_tree.insert("", "end", values=(factor, value, flag))
            dialog.destroy()

        ttk.Button(dialog, text="确认", command=confirm).pack(pady=10)

    def on_factor_double_click(self, event):
        """双击因子表格行进行编辑"""
        item = self.factor_tree.identify_row(event.y)
        if item:
            self.edit_factor(item)

    def remove_factor(self):
        """删除选中因子"""
        selected = self.factor_tree.selection()
        if selected:
            self.factor_tree.delete(selected)

    def add_sample_factors(self):
        """添加示例因子"""
        sample_factors = [
            ("e01202", "0.0", "N"),
            ("e01005", "0.0", "N"),
            ("e01201", "0.0", "N"),
            ("e01203", "0.0", "N"),
            ("e01204", "0.0", "N")
        ]
        for factor in sample_factors:
            self.factor_tree.insert("", "end", values=factor)

    def on_data_type_changed(self, *args):
        """数据类型变化时的回调函数"""
        data_type = self.data_type.get()
        if data_type == "实时数据":
            # 实时数据时禁用DataTime输入框并清空
            self.datetime_entry.config(state="disabled")
            self.datetime_entry.delete(0, tk.END)
        else:
            # 非实时数据时启用DataTime输入框
            self.datetime_entry.config(state="normal")

    def send_message(self):
        """发送报文"""
        try:
            ip = self.ip_entry.get()
            port = int(self.port_entry.get())
            mn = self.mn_entry.get()
            data_type = self.data_type.get()
            st = self.st_entry.get()
            flag = self.flag_entry.get()

            # 获取因子数据
            factor_data = {}
            for item in self.factor_tree.get_children():
                values = self.factor_tree.item(item, "values")
                if values[0]:  # 因子编码不为空
                    factor_data[values[0]] = {
                        "value": values[1],
                        "flag": values[2]
                    }

            if not factor_data:
                messagebox.showwarning("警告", "请至少添加一个因子")
                return

            # 处理DataTime
            if data_type == "实时数据":
                # 实时数据使用当前时间
                import datetime
                data_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
            else:
                # 非实时数据使用用户输入的时间
                data_time = self.datetime_entry.get().strip()
                if not data_time:
                    messagebox.showwarning("警告", "非实时数据需要输入DataTime")
                    return
                # 校验时间格式
                try:
                    datetime.datetime.strptime(data_time, "%Y%m%d%H%M%S")
                except ValueError:
                    messagebox.showwarning("警告", "DataTime格式错误，应为YYYYMMDDHHMMSS")
                    return

            # 生成HJ212报文
            message = hj212_protocol.generate_hj212_message(
                mn, factor_data, data_type=data_type, st=st, flag=flag, data_time=data_time
            )

            # 记录日志
            self.log(f"生成报文:\n{message}")

            # 发送TCP报文
            threading.Thread(
                target=self.send_tcp_message,
                args=(ip, port, message),
                daemon=True
            ).start()

        except Exception as e:
            self.log(f"错误: {str(e)}")

    def send_tcp_message(self, ip, port, message):
        """发送TCP报文"""
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.connect((ip, port))
                s.sendall(message.encode('utf-8'))
                response = s.recv(1024).decode('utf-8')
                self.log(f"发送成功! 服务器响应:\n{response}")
        except Exception as e:
            self.log(f"发送失败: {str(e)}")

    def log(self, message):
        """记录日志"""
        self.log_text.insert(tk.END, message + "\n\n")
        self.log_text.see(tk.END)


if __name__ == "__main__":
    root = tk.Tk()
    app = Hj212SenderApp(root)
    root.mainloop()